package com.micro.boot.interceptor;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.micro.boot.common.dialect.Dialect;
import com.micro.boot.common.dialect.MySQLDialect;
import com.micro.boot.common.dialect.OracleDialect;
import com.micro.boot.common.page.PageQuery;

/**
 * @Title:
 *         <P>
 *         PageInterceptor.java
 *         </P>
 * @Package
 *          <P>
 *          com.micro.boot.interceptor
 *          </P>
 * @Description:
 *               <P>
 *               分页拦截器
 *               </P>
 * @author renweiping
 * @date 2018年9月19日 下午2:52:45
 * @version 1.0
 */
@Intercepts({
		@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class PageInterceptor implements Interceptor {

	private static final Logger logger = LoggerFactory.getLogger(PageInterceptor.class);

	/*
	 * (non-Javadoc) 拦截器要执行的方法
	 */
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
				SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());

		BoundSql boundSql = statementHandler.getBoundSql();
		Object params = boundSql.getParameterObject();

		if (params instanceof PageQuery && ((PageQuery) params).isEnablePage()) {

			PageQuery pageQuery = (PageQuery) params;
			String originalSql = boundSql.getSql(); // 原始SQL

			Configuration configuration = (Configuration) metaObject.getValue("delegate.configuration");

			String databaseType = null;
			try {
				databaseType = configuration.getVariables().getProperty("dialect").toUpperCase();
			} catch (Exception e) {

				databaseType = "MYSQL";
			}
			if (databaseType == null) {
				throw new RuntimeException("the value of the dialect property in configuration.xml is not defined : "
						+ /*
							 * configuration.getVariables().getProperty(
							 * "dialect")
							 */ "");
			}

			Dialect dialect = null;
			if ("ORACLE".equals(databaseType)) {
				dialect = new OracleDialect();
			} else if ("MYSQL".equals(databaseType)) {
				dialect = new MySQLDialect();
			} else if ("SQLSERVER".equals(databaseType)) {
				dialect = new com.micro.boot.common.dialect.MySQLServerDialect();
			}

			metaObject.setValue("delegate.boundSql.sql",
					dialect.getLimitString(originalSql, pageQuery.getPage(), pageQuery.getPageSize()));// rowBounds.getOffset(),
																										// rowBounds.getLimit()));
			metaObject.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);
			metaObject.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);
			if (logger.isDebugEnabled()) {
				BoundSql boundSqlModify = statementHandler.getBoundSql();
				logger.debug("生成分页SQL : " + boundSqlModify.getSql());
			}
			return invocation.proceed();
		}
		return invocation.proceed();
	}

	/*
	 * (non-Javadoc) 拦截器需要拦截的对象
	 */
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	/*
	 * (non-Javadoc) 设置初始化的属性值
	 */
	public void setProperties(Properties properties) {

	}

}
